/*
    TV grabber voor Nederland
    Copyright (C) 2007-2008  Lars Teunissen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <unistd.h>
#include <libgen.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
#include <curl/curl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <time.h>
#include <locale.h>
#include "alg.h"
#include "main.h"
#include "config.h"
#include "cache.h"
#include "tvgids.h"
#include "upc.h"
//#include "sbs.h"
#include "skynet.h"
#include "imdb.h"

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
extern int aantalimdb;

// timezone tijd
void settz(void)
{
	time_t curtime;
	struct tm *loctime;
	curtime = time(NULL);
	loctime = localtime(&curtime);
	if (loctime->tm_isdst == 1)
		tz++;
	else if (loctime->tm_isdst == -1 && !stil)
		fprintf(stderr,
			"Winter-/zomertijd niet gespecificeerd!\n");
	sys_jaar = loctime->tm_year + 1900;
	sys_maand = loctime->tm_mon + 1;
	sys_dag = loctime->tm_mday;
	sys_wdag = loctime->tm_wday;

}


static struct option long_options[] = {
	{"description", no_argument, 0, 'd'},
	{"capabilities", no_argument, 0, 'c'},
	{"help", no_argument, 0, 'h'},
	{"quiet", no_argument, 0, 'q'},
	{"output", required_argument, 0, 'o'},
	{"days", required_argument, 0, 'a'},
	{"offset", required_argument, 0, 'f'},
	{"available_channels", no_argument, 0, 'p'},
	{"printconfig", no_argument, 0, 'r'},
	{"configure", no_argument, 0, 'b'},
	{"config-file", required_argument, 0, 'e'},
	{"preferredmethod", no_argument, 0, 'g'},
	{"cache", required_argument, 0, 'i'},
	{"emptycache", no_argument, 0, 'j'},
	{"list-channels", no_argument, 0, 'k'},
	{"icons", no_argument, 0, 'l'},
	{"imdb", required_argument, 0, 'm'},
	{"connect", required_argument, 0, 'n'},
	{0, 0, 0, 0}
};

void syntax(char *prog)
{
	printf("Syntax %s:\n", prog);
	printf("  --help\t\t\t: Deze help\n");
	printf("  --description\t\t\t: Omschrijving / versie\n");
	printf("  --capabilities\t\t: XMLTV capabilities\n");
	printf("  --quiet\t\t\t: Alleen errors naar stderr\n");
	printf("  --days <nr>\t\t\t: Aantal dagen om te grabben\n");
	printf("  --output <outputfile>\t: Uitvoer naar bestand\n");
	printf
	    ("  --offset <nr>\t\t\t: Start grabben vanaf vandaag plus <nr>\n");
	//printf("  --available_channels\t\t: Welke channels kan %s grabben\n", prog);
	printf
	    ("  --list-channels\t\t: Channels in config in xml-formaat\n");
	printf
	    ("  --printconfig\t\t\t: Print configuratiebestand, o.a. xmltv-id\n");
	printf("  --configure\t\t\t: Manuele configuratie\n");
	printf
	    ("  --config-file <configfile>\t: Configuratie-bestand (default $HOME/.tv_grab_ nl_C/tv_grab_nl_C.conf)\n");
	printf("  --preferredmethod\t\t: allatonce\n");
	printf("  --cache <cachefile>\t\t: Gebruike cache file\n");
	printf
	    ("  --emptycache\t\t\t: Leegmaken cache file alvorens data op te halen (requires --cache)\n");
	printf("  --icons\t\t\t: zenderlogo's\n");
	printf("  --imdb <imdb directory>\t: starrating/imdb ophalen\n");
	printf
	    ("  --connect <nr>\t\t: Aantal simultane connecties naar epg-provider\n");
	printf("\n\tOpmerkingen:\n");
	printf("\t- Maximaal aantal grab dagen is %d\n", MAXDAYS);
	printf
	    ("\t- Proxy d.m.v. environmentvariabele http_proxy=http://<proxy>:<poort>\n");
	printf
	    ("\t- %s maakt %d gelijktijdige verbindingen naar elke \n\t   geconfigureerde epg-provider(overrule via --connect)\n",
	     prog, MAXCONN);
	printf("\t- Time-out op http is %d seconden\n", TIMEOUT);
	printf
	    ("\t- --list-channels --icons geeft snel een xml-output voor channellogo's\n");
	printf("\t- Vanaf r38 is er een default config directory $HOME/.tv_grab_ nl_C (voor config, cache en imdb)\n");
}

void capabilities(void)
{
	printf("baseline\n");
	printf("manualconfig\n");
//      printf("apiconfig\n");
	printf("preferredmethod\n");
	printf("cache\n");
}

main(int argc, char *argv[])
{
	struct rusage usage;	//stats over systeemgebruik
	time_t progstart, progend;
	extern channel channelsconf[];
	//extern channel channelsconf2[];
	extern channel channels[];
	extern char imdbdir[];
	char *prog = basename(argv[0]);
	//tellertje
	int tel, tel2, tel3;
	int c;
	//--connect
	int connect_in = 0;
	//--configure
	short config = 0;
	// Stop alle config in 1 hidden dir
	char configdir[255];
	sprintf(configdir, "%s/.tv_grab_nl_C", getenv("HOME"));
	//--config-file
	char configfile[255];
	short printconf = 0;
	//--imdb 
	char imdbmap[255];
	imdbmap[0] = '\0';
	//--cache 
	char cachetemplate[255];
	sprintf(cachefile, "%s/%s/tv_grab_nl_C.cache", getenv("HOME"), configdir);
	// aantal dagen gespecificeerd door user : --days
	int days_in;
	//char *optstring= "+a:dcmhqo:" ;
	char *optstring = "";
	char *outputfile = NULL;
	int option_index = 0;
	//extern FILE *configfp;
	// channellijst in xml
	short listchan = 0;

	//char buffer[1024];

	//thread-id's
	int tid[500], status[500];
	pthread_t threads[500];

	struct stat stbuf;

	progstart = time(NULL);
	setlocale(LC_ALL, "ISO-8859-1");

	mkdir(configdir, S_IRWXU);
	if(!chdir(configdir)) {
		sprintf(configfile, "%s/tv_grab_nl_C.conf", configdir);
		sprintf(cachefile, "%s/tv_grab_nl_C.cache", configdir);
		sprintf(imdbdir, "%s/imdb", configdir);
	} else {
		sprintf(configfile, "%s/tv_grab_nl_C.conf", getenv("HOME"));
		sprintf(cachefile, "%s/tv_grab_nl_C.cache", getenv("HOME"));
		sprintf(imdbdir, "%s/imdb_C", getenv("HOME"));
	}

	while ((c = getopt_long_only(argc, argv, optstring,
				     long_options, &option_index)) != -1) {
		switch (c) {
		case 'a':	//--days
			for (tel = 0; optarg[tel] != '\0'; tel++) {
				if (tel == 0 && optarg[tel] == '-')
					continue;
				if (!isdigit(optarg[tel])) {
					fprintf(stderr,
						"Invalid option: %s\n",
						optarg);
					exit(1);
				}
			}
			days_in = atoi(optarg);
			if (days_in > MAXDAYS)
				days = MAXDAYS;
			else if (days_in > 0)
				days = days_in;
			else if (days_in <= 0)
				days = 0;
			break;
		case 'f':	//--offset
			for (tel = 0; optarg[tel] != '\0'; tel++) {
				if (!isdigit(optarg[tel])) {
					fprintf(stderr,
						"Invalid option: %s\n",
						optarg);
					exit(1);
				}
			}
			offset = atoi(optarg);
			break;
		case 'd':	//--description
			printf("Holland (%s versie: SVN %s)\n", NAAM, VERSION);
			exit(0);
		case 'c':	//--capabilities
			capabilities();
			exit(0);
		case 'b':	//--configure
			config = 1;
			break;
		case 'r':	//--printconfig
			printconf = 1;
			break;
		case 'i':	//--cache
			sprintf(cachefile, "%s", optarg);
			if (!cache)
				cache = 1;
			break;
		case 'j':	//--emptycache
			emptycache = 1;
			break;
		case 'e':	//--config-file
			sprintf(configfile, "%s", optarg);
			break;
		case 'g':	//--preferredmethod
			printf("allatonce\n");
			exit(0);;
		case 'k':	//--list-channels
			listchan = 1;
			break;
		case 'l':	//--icons
			icon = 1;
			break;
		case 'm':	//--imdb
			sprintf(imdbmap, "%s", optarg);
			if (!imdb)
				imdb = 1;
			break;
		case 'n':	//--connect
			for (tel = 0; optarg[tel] != '\0'; tel++) {
				if (tel == 0 && optarg[tel] == '-')
					continue;
				if (!isdigit(optarg[tel])) {
					fprintf(stderr,
						"Invalid option: %s\n",
						optarg);
					exit(1);
				}
			}
			connect_in = atoi(optarg);
			if (connect_in > MAXCONN)
				mconnect = MAXCONN;
			else if (connect_in > 0)
				mconnect = connect_in;
			else if (connect_in <= 0)
				mconnect = 1;
			break;
			case 'q':	//--quiet
			stil = 1;
			break;
		case 'o':	//--output
			outputfile = strdup(optarg);
			break;
		case 'h':	//--help
			syntax(prog);
			exit(0);
		default:
			exit(1);
			break;
		}

	}

	// redirect output: --output XXX
	if (outputfile) {
		if (!freopen(outputfile, "w+", stdout)) {
			perror("--output");
			exit(2);
		}
	}
	//curl initialiseren
	if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
		fprintf(stderr, "curl_global_init mislukt! Abort!\n");
		exit(3);
	}
	//configureren
	if (config)
		exit(configure(configfile));

	if (!readconfig(configfile)) {
		fprintf(stderr,
			"Misschien \"%s --configure\" nog uitvoeren?\n",
			prog);
		exit(3);
	}
	if (!stil)
		fprintf(stderr,
			"%s\n %s (%s) comes with ABSOLUTELY NO WARRANTY;\n This is free software, and you are welcome to redistribute it\n under certain conditions.\n\n",
			COPYRIGHT, NAAM, VERSION);
	//Timezone
	settz();

	if (printconf) {
		for (tel = 0; channelsconf[tel].id != NULL; tel++) {
			if (channelsconf[tel].provider == 0)
				printf
				    ("XmltvID=%s.tvgids.nl , Zender=\"%s\"\n",
				     channelsconf[tel].id,
				     channelsconf[tel].omschrijving);
			else if (channelsconf[tel].provider == 1)
				printf
				    ("XmltvID=%s.upclive.nl , Zender=\"%s\"\n",
				     channelsconf[tel].id,
				     channelsconf[tel].omschrijving);
/* layout website is veranderd omstreeks 19-10-2010
			else if (channelsconf[tel].provider == 3)
				printf
				    ("XmltvID=%s.skynet.be , Zender=\"%s\"\n",
				     channelsconf[tel].id,
				     channelsconf[tel].omschrijving);
*/
		}
		exit(0);
	}
	//cache
	if (cache) {
		if (!(cachefp = fopen(cachefile, "a+"))) {
			perror("--cache");
			cache = 0;
		} else if (emptycache) {
			if (ftruncate(fileno(cachefp), 0) == -1)
				perror("emptycache");
			rewind(cachefp);
		}
		sprintf(cachetemplate, "%sXXXXXX", cachefile);
		cachetmp = fdopen(mkstemp(cachetemplate), "w+");
		if (!cachetmp) {
			perror("tmp cachefile");
			cache = 0;
		}
		if (!stil)
			fprintf(stderr, "Gebruik caching met %s\n.",
				cachefile);
	} else if (!cache && emptycache) {
		if (!stil)
			fprintf(stderr, "--emptycache needs --cache!!\n");
	}
	//start xml en channelinfo in xml 
	printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
	//printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
	printf("<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n");
	printf
	    ("<tv generator-info-name=\"%s %s\" generator-info-url=\"http://home.tiscali.nl/~lteunissen/tv_grab_nl_C\">\n",
	     NAAM, VERSION);
	for (tel = 0; channelsconf[tel].id != NULL; tel++) {
		if (channelsconf[tel].provider == 1)
			printf(" <channel id=\"%s.upclive.nl\">\n",
			       channelsconf[tel].id);
//              else if (channelsconf[tel].provider == 2)
//                      printf(" <channel id=\"%s.sbs.nl\">\n",
//                             channelsconf[tel].id);
//		else if (channelsconf[tel].provider == 3)
//			printf(" <channel id=\"%s.skynet.be\">\n",
//			       channelsconf[tel].id);
		else
			printf(" <channel id=\"%s.tvgids.nl\">\n",
			       channelsconf[tel].id);
		printf("  <display-name lang=\"nl\">%s</display-name>\n",
		       channelsconf[tel].omschrijving);
		// logo's
		if (icon) {
			if (channelsconf[tel].icon)
				printf("  <icon src=\"%s\" />\n",
				       channelsconf[tel].icon);
			else if (!channelsconf[tel].provider) {
				for (tel2 = 0; channels[tel2].id != NULL;
				     tel2++) {
					if (!strcmp
					    (channels[tel2].id,
					     channelsconf[tel].id)) {
						if (channels[tel2].icon)
							printf
							    ("  <icon src=\"%s\" />\n",
							     channels
							     [tel2].icon);
					}
				}
			}
		}
		printf(" </channel>\n");
	}
	fflush(stdout);
	if (listchan || days_in == -1) {
		printf("</tv>\n");
		exit(0);
	}
	tel2 = 0;
	//imdb
	if (imdb) {
		if (imdbmap[0] != '\0')
			strcpy(imdbdir, imdbmap);
		if (!stil)
			fprintf(stderr,
				"IMDB data controleren/updaten...\n");
		pthread_mutex_lock(&mymutex);
		tid[tel2] = pthread_create(&threads[tel2],
					   NULL, (void *) &init_imdb,
					   NULL);
		pthread_mutex_unlock(&mymutex);
		tel2++;
	}

	if (!connect_in)
		mconnect = MAXCONN;
	if (!stil)
		fprintf(stderr, "%d connecties per provider gebruiken\n",
			mconnect);

	for (tel = 0; channelsconf[tel].id != NULL; tel++) {
		// Upc
		if (channelsconf[tel].provider == 1) {
			tid[tel2] = pthread_create(&threads[tel2],
						   NULL,
						   (void *) &upclive_nl,
						   &channelsconf[tel]);
/*
		} else if (channelsconf[tel].provider == 2) {
		// !!!! sbs6.sbs.nl levert geen complete tvgids meer !!!
			continue;
			tid[tel2] = pthread_create(&threads[tel2],
						   NULL, (void *) &sbs_nl,
						   &channelsconf[tel]);
*/
			// Skynet:
		} else if (channelsconf[tel].provider == 3) {
			tid[tel2] = pthread_create(&threads[tel2],
						   NULL, (void *) &skynet,
						   &channelsconf[tel]);
		} else {
			// Tvgids.nl
			tid[tel2] = pthread_create(&threads[tel2],
						   NULL,
						   (void *) &tv_gids_nl,
						   &channelsconf[tel]);
		}
		tel2++;
	}
	for (tel3 = 0; tel2 != 0 && tel3 < tel2; tel3++)
		pthread_join(threads[tel3], (void **) &status[tel3]);
	if (!stil)
		fprintf(stderr, "\n");

	printf("</tv>\n");

	if (cache) {
		cleancache();
		fclose(cachefp);
		fclose(cachetmp);
		if (!stat(cachetemplate, &stbuf)) {
			if (stbuf.st_size > 0) {
				unlink(cachefile);
				rename(cachetemplate, cachefile);
			}
		}
	}

	if (!stil) {
		fprintf(stderr,
			"\n\t###################-INFO-#######################\n\n");
		fprintf(stderr,
			"\t          Statistiek:                           \n");
		fprintf(stderr,
			"\t          %lu programma's online opgehaald.      \n",
			aantalprog);
		fprintf(stderr,
			"\t          %lu programma's uit cache opgehaald.   \n",
			aantalcache);
		fprintf(stderr,
			"\t          %d hits uit imdb gebruikt.   \n",
			aantalimdb);
		progend = time(NULL);
		fprintf(stderr, "\t          Runtime was %ld seconden.\n",
			(long) progend - (long) progstart);
		fprintf(stderr,
			"\n\t###################-INFO-#######################\n");
	}
	exit(0);
}
